<?php

class Workset_View_Helper_JQueryGrid extends ZendX_JQuery_View_Helper_UiWidget {

    protected $_loadJQueryGrid = true;

    protected $_tableId = null;

    protected $_pagerId = null;

    protected $_navGrid = false;

    protected $_vars = array();

	protected $_invokeParams = null;

    protected $_init = true;

    /**
     * Массив стандартных опций для jqGrid
     *
     * @var array
     */
    public $gridOptions = array(
        'url'       	=> null,
        'datatype'  	=> 'json',
        'colNames'  	=> array(),
        'colModel'  	=> array(),
        'rowNum'    	=> 20,
        'rowList'   	=> array(10,20,40,80,160),
        'pager'     	=> null,
        'sortname'  	=> null,
    	'height'		=> 'auto',
    	'viewrecords'	=> true,
    	'autowidth'		=> true,
    );

    /**
     * Массив со списком отображаемых кнопок навигации
     *
     * @var array
     */
    public $navButtons = array(
        'view'      => false,
        'search'    => false,
        'add'       => true,
        'edit'      => true,
        'del'       => true,
        'refresh'   => true,
    );

    /**
     * Массив с опциями для кнопок навигации
     *
     * array(
     *      кодКнопки => массив опций
     * )
     *
     * @var array
     */
    public $navButtonOptions = array(
        'search'    => array(
            'multipleSearch' => true
        ),
        'add'       => null,
        'edit'      => null,
        'del'       => null,
        'refresh'   => null,
        'view'      => null
    );

    /**
     * Массив со списком дополнительных кнопок навигации,
     * создаваемых через метод navButtonAdd в API jqGrid
     *
     * array(
     *      ID_Кнопки => массив опций кнопки
     * )
     * 
     * @var array
     */
    public $customButtons = array();

    /**
     * Массив со списком методов, которые будут вызваны после
     * создания грида.
     *
     * array(
     *      ...
     *      array(
     *          'method' => Имя_Метода,
     *          'args' => массив аргументов метода
     *      ),
     *      ...
     * )
     *
     * Каждый метод в js-коде вызывается через API jqGrid:
     * ...
     * jQuery("#grid_id").jqGrid('имя_метода', parameter1,...parameterN );
     * ...
     *
     * @var array
     */
    public $methods = array();

    /**
     * Массив со списком подключаемых js-файлов
     *
     * @var array
     */
    public $gridScripts = array(
        '/js/jqgrid/i18n/grid.locale-ru.js'
    );

    /**
     * Путь к jqGrid от корня сайта
     *
     * @var string
     */
    public $gridScriptFile = '/js/jqgrid/jquery.jqGrid.min.js';

	/**
     * Массив со списком подключаемых css-файлов
     *
     * @var array
     */
    public $gridStyles = array(
        '/css/jqgrid/ui.jqgrid.css',
        '/css/jqgrid/ui.multiselect.css'
    );

    /**
     * Указывает, нужно ли обрабатывать js-выражения, переданные, как объект Zend_Json_Expr
     * при генерации js-кода с момощью Zend_Json.
     *
     * Пример из документации Zend Framework
     *
     *
     *   $data = array(
     *      'onClick' => new Zend_Json_Expr('function() {'
     *          . 'alert("I am a valid javascript callback '
     *          . 'created by Zend_Json"); }'),
     *
     *      'other' => 'no expression',
     *   );
     *
     *   $jsonObjectWithExpression = Zend_Json::encode(
     *      $data,
     *      false,
     *      array('enableJsonExprFinder' => true)
     *   );
     *
     * @var bool
     */
    public $enableJsonExprFinder = true;

    function gridComplete($flag = true) {
        $this->_init = (bool)$flag;
        return $this;
    }

	function invokeParams($params) {
		$this->_vars['invokeParams'] = Zend_Json::encode($params, true, $this->_getEncodeOptions());
		return $this;
	}

    function JQueryGrid($id = null, $pagerId = null, $options = array()) {
        if (empty($id)) {
            return $this;
        } else {
            return $this->render($id, $pagerId, $options);
        } 
    }

	function renderHtml($escape = false) {
		$xhtml = sprintf('<table id="%s" class="scroll"></table>', $this->_tableId);

        if ($this->_navGrid && $this->_pagerId) {
            $xhtml .= sprintf('<div id="%s"></div>', $this->_pagerId);
        }

		if ($escape) {
			$xhtml = addslashes($xhtml);	
		}

        return $xhtml;
	}

	function renderOptions() {
		$exprOptions = $this->_getEncodeOptions();
		return Zend_Json::encode($this->gridOptions, false, $exprOptions);
	}

	function renderNavGridButtons() {
		$exprOptions = $this->_getEncodeOptions();
		return Zend_Json::encode($this->navButtons, false, $exprOptions);
	}

    function renderNavGrid($invokeGridId = null, $invokePagerId = null, $passAsArg = false) {

        $gridId = null !== $invokeGridId ? $invokeGridId : $this->_tableId;
        $pagerId = null !== $invokePagerId ? $invokePagerId : $this->_pagerId;

        if ($this->_navGrid && $pagerId) {

            if (true == $passAsArg) {
                $psPager = $psGrid = '%s';
            } else {
                $psPager = $psGrid = '"#%s"';
            }

            $exprOptions = $this->_getEncodeOptions();

            $jsEditButtonOpt = isset($this->navButtonOptions['edit']) ? Zend_Json::encode($this->navButtonOptions['edit'], false, $exprOptions) : '{}';
            $jsDelButtonOpt = isset($this->navButtonOptions['del']) ? Zend_Json::encode($this->navButtonOptions['del'], false, $exprOptions) : '{}';
            $jsViewButtonOpt = isset($this->navButtonOptions['view']) ? Zend_Json::encode($this->navButtonOptions['del'], false, $exprOptions) : '{}';
            $jsAddButtonOpt = isset($this->navButtonOptions['add']) ? Zend_Json::encode($this->navButtonOptions['add'], false, $exprOptions) : '{}';
            $jsSearchButtonOpt = isset($this->navButtonOptions['search']) ? Zend_Json::encode($this->navButtonOptions['search'], false, $exprOptions) : '{}';

            $jsCode = array(sprintf('%s('.$psGrid.')', ZendX_JQuery_View_Helper_JQuery::getJQueryHandler(), $gridId));
            $jsCode[] = sprintf('jqGrid("navGrid", '.$psPager.', %s, %s, %s, %s, %s, %s)',
                $pagerId,
                Zend_Json::encode($this->navButtons, false, $exprOptions),
                $jsEditButtonOpt,
                $jsAddButtonOpt,
                $jsDelButtonOpt,
                $jsSearchButtonOpt,
                $jsViewButtonOpt
            );

            foreach ($this->customButtons as $id => $options) {
                $jsOptions = Zend_Json::encode($options, false, $exprOptions);
                $jsCode[] = sprintf('jqGrid("navButtonAdd", '.$psPager.', %s)', $pagerId, $jsOptions);
            }

            return implode('.', $jsCode);
        }
        return '';
    }

	function addFiles() {
		foreach ($this->gridStyles as $file) {
			$this->jquery->addStylesheet($file);
		}

		foreach ($this->gridScripts as $file) {
			$this->jquery->addJavascriptFile($file);
		}

		$this->jquery->addJavascriptFile($this->gridScriptFile);
	}

    function render($id = null, $pagerId = null, $options = array()) {
        if (null !== $id) {
            $this->setTableId($id);
        }

        if (null !== $pagerId) {
            $this->setPagerId($pagerId);
        }

        if (!empty($options)) {
            $this->setOptions($options);
        }

        if (!is_string($this->_tableId)) {
            return '';
        }

        $this->_init();

        $exprOptions = $this->_getEncodeOptions();

        if ($this->_loadJQueryGrid) {
            $this->addFiles();
        }

        $jsCode = sprintf('
            %s("#%s").jqGrid(%s)
        ',
            ZendX_JQuery_View_Helper_JQuery::getJQueryHandler(),
		    $this->_tableId,
		    $this->renderOptions()
        );

        $this->jquery->addOnLoad($jsCode);

        //рендеринг navgrid
        if ($this->_navGrid) {
            $jsCode = $this->renderNavGrid();
            $this->jquery->addOnLoad($jsCode);
        }

        //вызов дополнительных методов
        if ($this->methods) {
            $jsCode = array(sprintf('%s("#%s")', ZendX_JQuery_View_Helper_JQuery::getJQueryHandler(), $this->_tableId));
            foreach ($this->methods as $params) {
				if (!empty($params['args'])) {
                	$jsOptions = Zend_Json::encode($params['args'], false, $exprOptions);
                	$jsCode[] = sprintf('jqGrid("%s", %s)', $params['method'], $jsOptions);
				} else {
					$jsCode[] = sprintf('jqGrid("%s")' ,$params['method']);
				}
            }

            $jsCode = implode('.', $jsCode);
            $this->jquery->addOnLoad($jsCode);
        }

        return $this->renderHtml();
    }

    function __toString() {
        return $this->render();
    }

    function setTableId($id) {
        $id = str_replace('#', '', $id);
        $this->_tableId = (string)$id;
        return $this;
    }

    function setPagerId($id) {
        $id = str_replace('#', '', $id);
        $this->_pagerId = $id;
        return $this;
    }

    function loadJQueryGrid($flag = true) {
        $this->_loadJQueryGrid = (bool)$flag;
        return $this;
    }

    function setOptions($options) {
        $this->gridOptions = array_merge($this->gridOptions, $options);
        return $this;
    }

    function setGridScripts($scripts) {
        $this->gridScripts = (array)$scripts;
        return $this;
    }

    function setGridStyles($styles) {
        $this->gridStyles = (array)$styles;
        return $this;
    }

    function enableNavGrid($buttons = array(), $options = null) {
        $this->_navGrid = true;
        if (isset($buttons['all'])) {
           $keys = array_keys($this->navButtons);
           $values = array_fill(0, count($keys), (bool)$buttons['all']);
           $this->navButtons = array_merge($this->navButtons, array_combine($keys, $values));
           unset($buttons['all']);
        }

        $this->navButtons = array_merge($this->navButtons, $buttons);

        if (is_array($options)) {
            foreach ($options as $key => $opt) {
                $this->addNavButtonOptions($key, $opt);
            }
        }

        return $this;
    }

    function addNavButton($id, $options = array()) {
        if (!$this->_navGrid) {
            $this->enableNavGrid();
        }

        if (isset($this->navButtons[$id])) {
            $this->navButtons[$id] = true;
            if (!empty($options)) {
                $this->addNavButtonOptions($id, $options);
            }
        }
        elseif (!isset($this->customButtons[$id])) {
            $this->customButtons[$id] = $options;
        }
        
        return $this;
    }

    function addNavButtonOptions($id, $options) {
        if (!empty($this->navButtons[$id])) {
            if (is_array($this->navButtonOptions[$id])) {
                $this->navButtonOptions[$id] = array_merge($this->navButtonOptions[$id], (array)$options);
            } else {
                $this->navButtonOptions[$id] = (array)$options;
            }
        }
        return $this;
    }

    function addMethod($name, $args = null) {
        $this->methods[] = array(
            'method' => $name,
            'args' => $args
        );
        return $this;
    }

	function __get($name) {
		if ($name == 'tableId') {
			return $this->_tableId;
		}

		if ($name == 'pagerId') {
			return $this->_pagerId;
		}

		if (isset($this->_vars[$name])) {
			return $this->_vars[$name];
		}

		return null;
	}

	function __set($name, $value) {
		if ($name == 'tableId') {
			$this->setTableId($value);
			return;
		}

		if ($name == 'pagerId') {
			$this->setPagerId($value);
			return;
		}

		if (is_array($value)) {
			$value = Zend_Json::encode($value, true);
		}

		$this->_vars[$name] = (string)$value;
	}

	function getNewInstance() {
		$class = get_class($this);
		$instance = new $class();
		$instance->setView($this->view);

		return $instance;
	}

	protected function _getEncodeOptions() {
		$exprOptions = array();

        if ($this->enableJsonExprFinder) {
            $exprOptions['enableJsonExprFinder'] = true;
        }

		return $exprOptions;
	}

    protected function _init() {

		if (is_string($this->_pagerId) && empty($this->gridOptions['pager'])) {
			$this->gridOptions['pager'] = '#' . $this->_pagerId;
		}

        if (!$this->_init) {
            return;
        }

		//перегрузка таблицы после вставки в дерево
        if (!empty($this->gridOptions['treeGrid']) && !array_key_exists('afterInsertRow', $this->gridOptions)) {
            $this->gridOptions['afterInsertRow'] = new Zend_Json_Expr('
				function(rowId, rowData) {
					jQuery("#'.$this->_tableId.'").trigger("reloadGrid");
				}
			');
        }

        //обработка ошибки загрузки
        if (!array_key_exists('loadError', $this->gridOptions)) {
            $this->gridOptions['loadError'] = new Zend_Json_Expr('
                function(req, status, error) {
                    var data = jQuery.parseJSON(req.responseText);
                    //info_dialog(data.caption, data.message, null, {width:"226px"});
                    $("#jqu_dialog").text(data.message).dialog({
                        title: data.caption,
                        width: "680px"
                    });
                }
            ');
        }

        //dbl-click на строке для редактирования
        if (!array_key_exists('ondblClickRow', $this->gridOptions) && $this->navButtons['edit'] == true) {
            $this->gridOptions['ondblClickRow'] = new Zend_Json_Expr('
                function(id) {
                    jQuery("#'.$this->_tableId.'").jqGrid("editGridRow", id);
                }
            ');
        }

        //вывод сообщения об ошибке
        if (empty($this->navButtonOptions['add']['errorTextFormat'])) {
            $this->navButtonOptions['add']['errorTextFormat'] = new Zend_Json_Expr('
                function(req) {
                    var data = $.parseJSON(req.responseText);
                    if (data.message != "") {
                        return data.message;
                    } else {
                        return "Unknown error, status: " + req.status;
                    }
                }
            ');
        }

    }

}

?>